#include "gkt_board.h"
#include "gkt_os.h"
#include "gkt_debug.h"
#include "gkt_backboard.h"
#include "gkt_cat_eye.h"

#if defined(GKT_CONFIG_CAT_EYE_ENABLE) && GKT_CONFIG_CAT_EYE_ENABLE \
	&& (GKT_MODULE_LOC_BACKBOARD == GKT_CAT_EYE_LOCATION)

enum {
	CAT_EYE_OP_START = 0,
	CAT_EYE_OP_MAX	
};

#define CAT_EYE_SYNC_TIMEOUT	100

#if defined(GKT_CONFIG_CAT_EYE_ACTIVE_TIMEOUT_MS)
#define CAT_EYE_ACTIVE_TIMEOUT_MS	GKT_CONFIG_CAT_EYE_ACTIVE_TIMEOUT_MS
#else
#define CAT_EYE_ACTIVE_TIMEOUT_MS	2000
#endif

#if	(CAT_EYE_ACTIVE_TIMEOUT_MS != 0)

typedef struct {
	int	init_ok;
	gkt_cat_eye_status_e	status;
	gkt_mutex_t	mutex;
	gkt_soft_timer_t	timer_id;
	gkt_cet_eye_notify_fn	notify;
} cat_eye_bb_s;
static cat_eye_bb_s s_cat_eye_bb;

enum {
	CAT_EYE_START_RSP_STATUS = GKT_BB_APP_PACKET_MINSIZE,
	CAT_EYE_START_RSP_MAX
};
static void cat_eye_module_notify(int type, 

				const uint8_t *data, int length_retval)
{
	uint8_t opcode, status;
	
	opcode = data[GKT_BB_APP_PACKET_OPCODE];
	gkt_info("cat_eye_notify: type(%d), opcode(%u), length(%d)\n",
		type, opcode, length_retval);

	if (GKT_BB_NOTIFY_PEER == type) {
		if ((CAT_EYE_OP_START == opcode) 
			&& (length_retval >= CAT_EYE_START_RSP_MAX)) 
		{
			status = data[CAT_EYE_START_RSP_STATUS];
			gkt_info("cat_eye_notify: status(%u - %u)\n",
				s_cat_eye_bb.status, status);

			gkt_mutex_lock(s_cat_eye_bb.mutex, CAT_EYE_SYNC_TIMEOUT);
			if (s_cat_eye_bb.status != GKT_CAT_EYE_ST_STARTING) {
				gkt_mutex_unlock(s_cat_eye_bb.mutex);
				return;
			}

			if ((GKT_BB_STATUS_SUCCESS == status)
				|| (GKT_BB_STATUS_COMPLETE == status))
			{
				s_cat_eye_bb.status = GKT_CAT_EYE_ST_ACTIVE;
			}
			else if ((status != GKT_BB_STATUS_INPROCESS)
				&& (status != GKT_BB_STATUS_START))
			{
				s_cat_eye_bb.status = GKT_CAT_EYE_ST_INACTIVE;
			}

			if (s_cat_eye_bb.status != GKT_CAT_EYE_ST_STARTING) {
				gkt_mutex_unlock(s_cat_eye_bb.mutex);
				gkt_soft_timer_stop(s_cat_eye_bb.timer_id);

				if (s_cat_eye_bb.notify)
					(*s_cat_eye_bb.notify)(s_cat_eye_bb.status);
			}
			else
				gkt_mutex_unlock(s_cat_eye_bb.mutex);
		}
	}
	else if (length_retval < GKT_SUCCESS) {
		gkt_mutex_lock(s_cat_eye_bb.mutex, CAT_EYE_SYNC_TIMEOUT);
		if (s_cat_eye_bb.status != GKT_CAT_EYE_ST_STARTING) {
			gkt_mutex_unlock(s_cat_eye_bb.mutex);
			return;
		}
		s_cat_eye_bb.status = GKT_CAT_EYE_ST_INACTIVE;
		gkt_mutex_unlock(s_cat_eye_bb.mutex);

		gkt_soft_timer_stop(s_cat_eye_bb.timer_id);
		if (s_cat_eye_bb.notify)
			(*s_cat_eye_bb.notify)(GKT_CAT_EYE_ST_INACTIVE);
	}
}

static void cat_eye_timer_callback(void *params)
{
	gkt_mutex_lock(s_cat_eye_bb.mutex, CAT_EYE_SYNC_TIMEOUT);
	if (GKT_CAT_EYE_ST_STARTING == s_cat_eye_bb.status) {
		s_cat_eye_bb.status = GKT_CAT_EYE_ST_INACTIVE;
		gkt_mutex_unlock(s_cat_eye_bb.mutex);

		if (s_cat_eye_bb.notify)
			(*s_cat_eye_bb.notify)(GKT_CAT_EYE_ST_INACTIVE);
	}
	else
		gkt_mutex_unlock(s_cat_eye_bb.mutex);
}

void gkt_cat_eye_register_notify(gkt_cet_eye_notify_fn notify)
{
	s_cat_eye_bb.notify = notify;
}

gkt_cat_eye_status_e gkt_cat_eye_get_status(void)
{
	return s_cat_eye_bb.status;
}

int gkt_cat_eye_start(void)
{
	uint8_t data[GKT_BB_APP_PACKET_MINSIZE];
	int retval;

	gkt_info("cat_eye_start: <%d> status(%u)\n", 
		s_cat_eye_bb.init_ok, s_cat_eye_bb.status);

	if (!s_cat_eye_bb.init_ok)
		return GKT_ENOTINIT;

	gkt_mutex_lock(s_cat_eye_bb.mutex, 100);
	if (GKT_CAT_EYE_ST_ACTIVE == s_cat_eye_bb.status) {
		gkt_mutex_unlock(s_cat_eye_bb.mutex);
		return GKT_SUCCESS;
	}
	else if (GKT_CAT_EYE_ST_STARTING == s_cat_eye_bb.status) {
		gkt_mutex_unlock(s_cat_eye_bb.mutex);
		return GKT_EINPROCESS;
	}
	s_cat_eye_bb.status = GKT_CAT_EYE_ST_STARTING;
	gkt_mutex_unlock(s_cat_eye_bb.mutex);

	data[GKT_BB_APP_PACKET_MODULE_ID] = GKT_BB_MODULE_CAT_EYE;
	data[GKT_BB_APP_PACKET_OPCODE] = CAT_EYE_OP_START;
	retval = gkt_backboard_send_data(data, GKT_BB_APP_PACKET_MINSIZE);
	if ((GKT_SUCCESS == retval) || (GKT_EINPROCESS == retval)) {
		gkt_soft_timer_start(s_cat_eye_bb.timer_id, CAT_EYE_ACTIVE_TIMEOUT_MS);
		retval = GKT_EINPROCESS;
	}
	else
		s_cat_eye_bb.status = GKT_CAT_EYE_ST_INACTIVE;

	return retval;

}

int gkt_cat_eye_init(void)
{
	s_cat_eye_bb.init_ok = 0;
	s_cat_eye_bb.status = GKT_CAT_EYE_ST_INACTIVE;
	s_cat_eye_bb.notify = NULL;

	s_cat_eye_bb.mutex = gkt_mutex_create(0);
	if (!s_cat_eye_bb.mutex) {
		gkt_error("cat_eye: create mutex failed!\n");
		return GKT_ECREATE;
	}

	s_cat_eye_bb.timer_id = gkt_soft_timer_create(GKT_SOFT_TIMER_ONCE,
					cat_eye_timer_callback, NULL);
	if (!s_cat_eye_bb.timer_id) {
		gkt_error("cat_eye: create soft timer failed!\n");
		return GKT_ECREATE;
	}

	gkt_backboard_register_module(GKT_BB_MODULE_CAT_EYE,
			CAT_EYE_OP_MAX, cat_eye_module_notify);

	s_cat_eye_bb.init_ok = 1;
	
	return GKT_SUCCESS;
}

#else
int gkt_cat_eye_init(void)
{
	return GKT_SUCCESS;
}
int gkt_cat_eye_start(void)
{
	return GKT_SUCCESS;
}
void gkt_cat_eye_register_notify(gkt_cet_eye_notify_fn notify)
{
	gkt_unused(notify);
}
gkt_cat_eye_status_e gkt_cat_eye_get_status(void)
{
	return GKT_CAT_EYE_ST_ACTIVE;
}
#endif

#endif

